package com.learn.rpc.socket.proxy;

import com.learn.rpc.common.AdminUser;
import com.learn.rpc.common.IAdminUserService;
import com.learn.rpc.socket.proxy.RpcServer2;

import java.io.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.net.Socket;

/**
 * 代理类
 * @author wangxing
 * @version 2020/8/14 17:39 Administrator
 */
public class Stub {
    /**
     * 动态代理中进行远程调用
     */
    static InvocationHandler invocationHandler = (proxy, method, args) -> {
        String host = "localhost";
        Socket socket = new Socket(host, RpcServer2.PORT);
        //传递方法名称和方法参数到socket
        ObjectOutputStream  objectOutputStream= new ObjectOutputStream(socket.getOutputStream());

        String methodName = method.getName();
        Class[] parametersTypes = method.getParameterTypes();
        objectOutputStream.writeUTF(methodName);
        objectOutputStream.writeObject(parametersTypes);
        objectOutputStream.writeObject(args);
        objectOutputStream.flush();

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        DataOutputStream dataOutputStream = new DataOutputStream(outputStream);

        dataOutputStream.writeInt((Integer) args[0]);
        socket.getOutputStream().write(outputStream.toByteArray());
        socket.getOutputStream().flush();
        DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());


        Integer id = dataInputStream.readInt();
        String name = dataInputStream.readUTF();
        AdminUser adminUser = new AdminUser(id,name);


        dataOutputStream.close();
        socket.close();
        dataInputStream.close();
        outputStream.close();
        return adminUser;
    };
    /**
     * 直接传递对象
     */
    static InvocationHandler invocationHandlerObject = (proxy, method, args) -> {
        String host = "localhost";
        Socket socket = new Socket(host,RpcServer2.PORT);
        //传递方法名称和方法参数到socket
        ObjectOutputStream  objectOutputStream= new ObjectOutputStream(socket.getOutputStream());

        String methodName = method.getName();
        Class[] parametersTypes = method.getParameterTypes();
        objectOutputStream.writeUTF(methodName);
        objectOutputStream.writeObject(parametersTypes);
        objectOutputStream.writeObject(args);
        objectOutputStream.flush();

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        DataOutputStream dataOutputStream = new DataOutputStream(outputStream);

        dataOutputStream.writeInt((Integer) args[0]);
        socket.getOutputStream().write(outputStream.toByteArray());
        socket.getOutputStream().flush();
        ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());

        AdminUser adminUser = (AdminUser) objectInputStream.readObject();


        dataOutputStream.close();
        socket.close();
        objectInputStream.close();
        outputStream.close();
        return adminUser;
    };
    static public IAdminUserService getIAdminUserService(){
        Object service = Proxy.newProxyInstance(IAdminUserService.class.getClassLoader(),
                new Class[]{IAdminUserService.class},
                invocationHandler);
        System.out.println(service.getClass().getName());
        return (IAdminUserService)service;
    }
    static public IAdminUserService getIAdminUserServiceObject(){
        Object service = Proxy.newProxyInstance(IAdminUserService.class.getClassLoader(),
                new Class[]{IAdminUserService.class},
                invocationHandlerObject);
        System.out.println(service.getClass().getName());
        return (IAdminUserService)service;
    }
}
